package compiler;

import ast.Expression;
import ast.FunctionCall;
import ast.IntegerExpr;
import ast.Operation;
import ast.OperationType;
import ast.StringExpr;
import ast.Type;
import ast.Variable;

import compiler.Lexer.LexerContext;

public class Utils {

	/**
	 * Raises an error. The current implementation stops the compilation process
	 * @param msg The error message
	 * @param lexer The LexerContext used to get the line number where the error occourred
	 */
    static public void error(String msg, LexerContext context) {
        System.err.println("Error at line " + context.getLineNumber() + ": " + msg);
    }
    
	/**
	 * Raises an error. The current implementation stops the compilation process
	 * @param msg The error message
	 * @param lexer The LexerContext used to get the line number where the error occourred
	 * @param die if true, exits the program
	 */    
    static public void error(String msg, LexerContext context, boolean die) {
        Utils.error(msg, context);
        if (die)
            System.exit(1);
    }
    
	/**
	 * Checks if a given expression and type match. If they don't, an error is showed
	 * @param expr The expression to be tested.
	 * @param type The type to be tested.
	 * @return true if they don't match, false otherwise
	 */    
	public static boolean checkExpr(Expression expr, Type type) {
		boolean error = false;

		if (expr instanceof Variable) {
			if (((Variable) expr).getType() != type)
				error = true;
		} else if (expr instanceof Operation) {
			Operation operation = (Operation) expr;
			if (type == Type.STR)
				error = true;
			else if (type == Type.INT) {
				if (operation.getOperator().getType() != OperationType.ARITHMETICAL)
					error = true;
				else {
					error = error || checkExpr(operation.getLeftExpression(), Type.INT);
					error = error || checkExpr(operation.getRightExpression(), Type.INT);
				}
			} else if (type == Type.BOOL) {
				if (operation.getOperator().getType() == OperationType.COMPARISON) {
					error = error || checkExpr(operation.getLeftExpression(), Type.INT);
					error = error || checkExpr(operation.getRightExpression(), Type.INT);
				} else if (operation.getOperator().getType() == OperationType.LOGICAL) {
					error = error || checkExpr(operation.getLeftExpression(), Type.BOOL);
					error = error || checkExpr(operation.getRightExpression(), Type.BOOL);
				} else { 
					error = true;
				}
			}
		} else if (expr instanceof StringExpr) {
			if (type != Type.STR)
				error = true;
		} else if (expr instanceof IntegerExpr) {
			if (type != Type.INT)
				error = true;
		} else if (expr instanceof FunctionCall) {
			if (type != ((FunctionCall) expr).getFunctionType())
				error = true;
		}

		return error;
	}    
}
